use rand::seq::SliceRandom;
// 评估密码复杂度的库
use zxcvbn::zxcvbn;

// 使用const定义常量时, 必须显式的指定类型
const UPPER: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const LOWER: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
const NUMBERS: &[u8] = b"0123456789";
const SYMBOLS: &[u8] = b"!@#$%^&*";

pub fn process_genpass(
    length: u8, 
    uppercase: bool, 
    lowercase: bool, 
    numbers: bool, 
    symbols: bool
) -> anyhow::Result<()> {
    let mut rng = rand::thread_rng();
    let mut password = Vec::new();
    let mut chars = Vec::new();

    if uppercase {
        chars.extend_from_slice(UPPER);
        password.push(*UPPER.choose(&mut rng).expect("UPPER won't be empty"));
    }

    if lowercase {
        chars.extend_from_slice(LOWER);
        password.push(*LOWER.choose(&mut rng).expect("LOWER won't be empty"));
    }

    if numbers{
        chars.extend_from_slice(NUMBERS);
        password.push(*NUMBERS.choose(&mut rng).expect("NUMBERS won't be empty"));
    }

    if symbols {
        chars.extend_from_slice(SYMBOLS);
        password.push(*SYMBOLS.choose(&mut rng).expect("SYMBOLS won't be empty"));
    }

    for _ in 0..(length - password.len() as u8) {
        let s = chars.choose(&mut rng).expect("chars won't be empty");
        password.push(*s);
    }
    
    // 再次随机一下, 避免出现密码前4为是固定的模式
    password.shuffle(&mut rng);

    let password_str = String::from_utf8(password)?;
    // 用于输出到stdout
    println!("{}", password_str);

    let estimate = zxcvbn(&password_str, &[]);
    // 用于输出到stderr
    // 这样做的好处在于, 当使用类似: rcli genpass -l 16 | echo eprintln的输出不会通过管道符传递
    eprintln!("Password score: {}", estimate.score());

    Ok(())
}